#pragma once
#include <iostream>
#include "utility/index.hpp"
#include "request_access/index.hpp"
#include "data_access/index.hpp"
#include "components/index.hpp"
#include "actions.hpp"

using namespace std;
using namespace utility;

namespace components2 {
    class SupplyOrder : public components::EntityRequest {
    public:
        COMPONENT_INSTANCE_FUNCTION(SupplyOrder);

        SupplyOrder();

        any UpdateStatus();

        any Update2();

        any CancelReview();

        any GetSupplyOrder();

        any GetSupplyOrder2();

    private:
        EntityData getSupplyOrderEntity(EntityData& dict);

        vector<EntityData> getPurchaseSupply(const any &purchaseOrderId, const any& supplyOrderId);
        vector<EntityData> getPurchaseSupply2(const any &purchaseOrderId, const any& supplyOrderId);

        entity_access::EntityType *purchaseOrderEntity;
        entity_access::EntityType *viewSupplyOrderEntity;
    };

    SupplyOrder::SupplyOrder() {
        SET_METHOD_ACTION(UpdateStatus);
        SET_METHOD_ACTION(Update2);
        SET_METHOD_ACTION(CancelReview);
        SET_METHOD_ACTION(GetSupplyOrder);
        SET_METHOD_ACTION(GetSupplyOrder2);
        purchaseOrderEntity = entity_access::GetEntityType("PurchaseOrder");
        viewSupplyOrderEntity = entity_access::GetEntityType("ViewSupplyOrder");
    }

    std::any SupplyOrder::UpdateStatus() {
        EntityData dict = Request->RequestEntity.GetEntityData(Entity->Name);

        auto oldEntityData = SelectEntityByPrimaryKey(QueryRequest->PrimaryKeyValue);
        if (oldEntityData.Empty()) return Request->GetMessageMap("供应单不存在");

        auto msg = CompareVersion(dict, oldEntityData);
        if (!msg.empty()) return Request->GetMessageMap(msg);

        auto purchaseOrderId = oldEntityData.Get("PurchaseOrderId");

        bool blSucceed = true;
        try {
            DataBase->BeginTransaction();

            blSucceed = Actions::UpdateStatusAndReview(shared_from_this(), nullptr, dict, 2);

            if (blSucceed) DataBase->CommitTransaction();
            else DataBase->RollbackTransaction();
        } catch (const std::exception &e) {
            DataBase->RollbackTransaction();
            throw MessageException(e.what(),"");
        }

        return GetSucceedMap(blSucceed);
    }

    any SupplyOrder::Update2() {
        auto dict = Request->RequestEntity.GetEntityData(Entity->Name);
        auto supplyOrder = getSupplyOrderEntity(dict);

        auto details = supplyOrder.GetEntityDataList("Details");
        if (details.empty()) return Request->GetMessageMap("商品明细供应数量不能都为0");

        auto oldEntityData = SelectEntityByPrimaryKey(purchaseOrderEntity, dict.Get("PurchaseOrderId"));
        if(oldEntityData.Empty()) return Request->GetMessageMap("采购订单不存在");

        EntityData purchaseOrder;
        purchaseOrder["RowVersion"] = dict.Get("PurchaseOrderRowVersion");

        auto msg = CompareVersion(purchaseOrder, oldEntityData);
        if (!msg.empty()) return Request->GetMessageMap(msg);

        Request->RequestEntity["SupplyOrder"] = supplyOrder;
        auto obj = Update();

        if (obj.ContainsKey("Succeed")) {
            EntityData updateEntityData;
            updateEntityData["UpdateDate"] = DateTime();
            updateEntityData["UpdateUser"] = Request->OperationUser;

            UpdateEntity(purchaseOrderEntity, GetQueryByPrimaryKey(purchaseOrderEntity, dict.Get("PurchaseOrderId")), updateEntityData);
        }

        return obj;
    }

    EntityData SupplyOrder::getSupplyOrderEntity(EntityData& dict) {
        EntityData data;

        data["SupplyOrderId"] = dict["SupplyOrderId"];
        data["SupplyDate"] = dict["SupplyDate"];
        data["Status"]=dict["Status"];
        data["Remark"] =  dict["Remark"];
        data["RowVersion"] =  dict["RowVersion"];                          

        auto details = dict.GetEntityDataList("Details");

        vector<EntityData> detailList;
        for (auto &d: details) {
            auto num = d.GetFloat("Num");
            if (num != 0) {
                EntityData detail;
                detail["Num"] = d["Num"];
                detail["DisplayIndex"] = d["DisplayIndex"];
                detail["MaterialProductId"] = d["MaterialProductId"];
                detailList.emplace_back(detail);
            }
        }

        data["Details"] = detailList;

        return data;
    }

    any SupplyOrder::CancelReview() {
        Actions::SetCancelReviewEntityData(shared_from_this());
        return UpdateStatus();
    }

    any SupplyOrder::GetSupplyOrder() {
        EntityData entityData = SelectEntityByPrimaryKey(viewSupplyOrderEntity, QueryRequest->PrimaryKeyValue);
        entityData.Remove("IsDelete");
        if(!entityData.Empty()) {
            entityData["Details"] = getPurchaseSupply(entityData.Get("PurchaseOrderId"), entityData.Get("SupplyOrderId"));
        }

        return entityData;
    }

    vector<EntityData> SupplyOrder::getPurchaseSupply(const any &purchaseOrderId, const any& supplyOrderId) {
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@PurchaseOrderId", purchaseOrderId);
        parameters->Add("@SupplyOrderId", supplyOrderId);

        auto query = make_shared<data_access::Query>();
        string sql = "with PurchaseSuppler as\n"
                     "(\n"
                     "SELECT PurchaseOrderId,a.MaterialProductId, sum(Num) SupplyNum FROM t_supplyorder_detail a,t_supplyorder b\n"
                     "where b.IsDelete=0 and a.SupplyOrderId=b.SupplyOrderId and b.PurchaseOrderId=@PurchaseOrderId and b.SupplyOrderId<>@SupplyOrderId\n"
                     "group by PurchaseOrderId,a.MaterialProductId\n"
                     "),\n"
                     "PurchaseSupplyDetail as\n"
                     "(\n"
                     "select a.*,ifnull(b.SupplyNum,0) SupplyNum,a.Num-ifnull(b.SupplyNum,0) BalanceNum,c.Status,d.Name ProductTypeName,e.Name MaterialProductName from t_PurchaseOrder_Detail a\n"
                     "inner join t_purchaseorder c on a.PurchaseOrderId=c.PurchaseOrderId \n"
                     "left join PurchaseSuppler b on a.PurchaseOrderId=b.PurchaseOrderId and a.MaterialProductId=b.MaterialProductId\n"
                     "left join t_materialproducttype d on a.ProductTypeId=d.ProductTypeId \n"
                     "left join t_materialproduct e on a.MaterialProductId=e.MaterialProductId\n"
                     "where a.PurchaseOrderId=@PurchaseOrderId\n"
                     ")\n"
                     "select PurchaseOrderId,ProductTypeName,a.MaterialProductId,MaterialProductName,a.Num PurchaseNum,SupplyNum+ifnull(f.Num,0) SupplyNum,BalanceNum,ifnull(f.Num,0) Num from \n"
                     "PurchaseSupplyDetail a\n"
                     "left join t_supplyorder_detail f on a.MaterialProductId=f.MaterialProductId and f.SupplyOrderId=@SupplyOrderId\n"
                     "where a.BalanceNum<>0 \n"
                     "order by a.DisplayIndex";

        query->SetSql(sql, parameters);

        return SelectEntities(query);
    }

    any SupplyOrder::GetSupplyOrder2() {
        auto query = GetQueryByPrimaryKey(viewSupplyOrderEntity,QueryRequest->PrimaryKeyValue);
        query->Select("SupplyOrderId,PurchaseOrderId,OrderCode,PurchaseOrderCode,SupplierName,PurchaseEmployeeName,Remark SupplyRemark,SupplyDate,RowVersion");
        EntityData entityData = SelectEntity(query);
        entityData.Remove("IsDelete");
        if(!entityData.Empty()) {
            entityData["Details"] = getPurchaseSupply2(entityData.Get("PurchaseOrderId"), entityData.Get("SupplyOrderId"));
        }

        return entityData;
    }

    vector<EntityData> SupplyOrder::getPurchaseSupply2(const any &purchaseOrderId, const any &supplyOrderId) {
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@PurchaseOrderId", purchaseOrderId);
        parameters->Add("@SupplyOrderId", supplyOrderId);

        auto query = make_shared<data_access::Query>("v_SupplyOrderDetail");
        query->Select("DetailId,MaterialProductId,ProductTypeName,MaterialProductName,PurchaseNum,SupplyNum");
        query->Where("where PurchaseOrderId=@PurchaseOrderId and SupplyOrderId=@SupplyOrderId", parameters);
        query->OrderBy("order by DisplayIndex");

        return SelectEntities(query);
    }
}